using System;
using System.Collections.Generic;
using CLELCore.Assembly.MethodHeaderDataSections.MethodHeaderDataSectionRows;

namespace CLELCore.Assembly.MethodHeaderDataSections
{
	public class MethodHeaderDataSection
	{
		public const byte SECT_EHTABLE = 0x1;
		public const byte SECT_OPTILTABLE = 0x2;
		public const byte SECT_FATFORMAT = 0x40;
		public const byte SECT_MORESECTS = 0x80;
		public const byte FAT_DATA_ROW_SIZE = 24;
		public const byte TINY_DATA_ROW_SIZE = 12;

		private bool _is_fat;
		private byte _flags;
		private int _section_size;
		private List<MethodHeaderDataSectionRow> _rows;

		public byte Flags
		{
			get
			{
				return _flags;
			}
			set
			{
				_flags = value;
			}
		}
		public int SectionSize
		{
			get
			{
				return _section_size;
			}
			set
			{
				_section_size = value;
			}
		}
		public List<MethodHeaderDataSectionRow> Rows
		{
			get
			{
				return new List<MethodHeaderDataSectionRow>(_rows);
			}
			set
			{
				if(value != null)
				{
					_rows = value;
				}
			}
		}

		public int Size
		{
			get
			{
				if(_rows != null && _rows.Count > 0)
				{
					if(_is_fat)
						return 4+(_rows.Count*_rows[0].Size);
					return 6+(_rows.Count*_rows[0].Size);
				}
				return 0;
			}
		}

		public bool IsFat
		{
			get
			{
				return _is_fat;
			}
		}

		public MethodHeaderDataSection(byte flags,int section_size)
		{
			_flags = flags;
			_section_size = section_size;
			_rows = new List<MethodHeaderDataSectionRow>();
			_is_fat = (_flags & MethodHeaderDataSection.SECT_FATFORMAT) == MethodHeaderDataSection.SECT_FATFORMAT;
		}

		public MethodHeaderDataSection(byte flags,int section_size,
			List<MethodHeaderDataSectionRow> rows)
		{
			_flags = flags;
			_section_size = section_size;
			_rows = new List<MethodHeaderDataSectionRow>(rows);
			_is_fat = (_flags & MethodHeaderDataSection.SECT_FATFORMAT) == MethodHeaderDataSection.SECT_FATFORMAT;
		}

		public void AddRow(MethodHeaderDataSectionRow row)
		{
			_rows.Add(row);
		}

		public MethodHeaderDataSectionRow GetRow(int row)
		{
			if(row >= 0 && row < _rows.Count)
				return _rows[row];
			return null;
		}

		public byte[] GetBytes(bool little_endian)
		{
			byte[] ret = new byte[Size];
			if(_rows != null && _rows.Count > 0)
			{
				ret[0] = _flags;
				bool sect_fat = (_flags & MethodHeaderDataSection.SECT_FATFORMAT) == MethodHeaderDataSection.SECT_FATFORMAT;
				int i;
				if(sect_fat)
				{
					if(little_endian)
						for(i = 0;i < 3;i++)
							ret[1+i] = Bits.ByteFromInt(i,_section_size);
					else
						for(i = 2;i >= 0;i--)
							ret[1+i] = Bits.ByteFromInt(i,_section_size);
				}
				else
				{
					ret[1] = Bits.ByteFromInt(0,_section_size);
					ret[2] = 0;
					ret[3] = 0;
				}
				int next = 4;
				int rows_count = _rows.Count;
				byte[] row_bytes;
				for(i = 0;i < rows_count;i++)
				{
					row_bytes = _rows[i].GetBytes(little_endian);
					Bits.SetBytes(next,ret,row_bytes);
					next += row_bytes.Length;
				}		
			}
			return ret;
		}
	}
}
